ARFoundationを腑分ける
概要
すげーーーでっかい上に邪魔な処理が多すぎる。
OnEnableに依存した処理が書かれまくっている。やめてくれ。
というわけで、ARFoundationをデフォルトで使うとどんなふうな構成になっているのか、を書く。
いや抽象化は大事なんすけど、抽象化の手段がピタゴラスイッチってのは勘弁してくれ、っていう話。
ちなみに負荷がすげーーー高いので原因を探していてこの記事を書く羽目になっている。
結論から書くと、ARFoundationに書いてあるコードはサンプルコードだ、あれをそのまま使って快適さを得られるケースは多分存在しない。
理解して分解して手で再構成すると本当に欲しい機能だけの低負荷なセットが作れる。
全体像が見えないシステム&サブシステム達、、、
具体例としてARFoundationを使ったAR空間上でのFaceTrackingをあげようと思う。
なんでAR空間上ってのが付くかって? デフォルトで生成できるFaceTrackingにはなんでかAR空間上の位置をトラックする機能がデフォでついてるんだよ。なんでだよ。
Hierarchy上で次のような構成になる。GameObject多いな~~Componentすげーー多いな~~~w
GO1
∟ ARSession
∟ ARInputManager
GO2
∟ ARSessionOrigin
∟ Camera参照
∟ ARFaceManager
∟ FacePrefab
GO3
∟ Camera
∟ ARPoseDriver
∟ ARCameraManager
だいたいこんな感じで書くと構成が伝わるかなあ、、、いやまああとでmiroとかで図を書く、、、、
ARFoundationは複数のComponentがそれぞれ独立して順不同に起動することでネットワークを形成して動きますっていうタイプのプロダクトで、
いろんなパーツがあるがそれらが好き勝手に初期化されて動作し全体像としてAR機能を形作っていく。
ARFoundationは端末の機能をSystem/Subsystemという「機能単位に構成された実機端末の各featureへのアクセッサ」を介して起動したり終了したりしており、
具体的には次のようなものがある。
・端末の回転やAR空間上での位置はXRInputSystem
・FaceTrackingはARKitFaceSubsystem
で、厄介なことに、じゃあXRInputSystemを起動すれば端末の回転とか位置が取れるんすよね?っていうと、そうなってない。なんでだよ。
端末の回転や位置を取るには、次の操作が次の順で必要。
1. XRInputSystemを端末から取得するためにOSごとの設定ファイルを書き、Assets以下に置く
2. XRInputSystemを起動する
3. ARSessionを起動する
4. ARSessionのstateがReadyになったら、実際の値を取得するDeviceをOSから取得する(InputDevices.GetDevicesWithCharacteristics)
5. Deviceから好きなタイミングで回転や位置を取得する
えーざっくりいうと、
・~InputSystemはOS側の「機能」を使うための前準備(な場合がある、全てのSystemに該当するわけではない)
・実際に~InputSystemから値を得ることはできず、ARSessionを起動したのち、Deviceを得ることができるタイミングが存在する
これはつまり
・ARジャイロ機能(適当)の有無を確認し、取得可能かチェックしたり取得可能状態になったりする
・ARSessionが各Systemの実際の動作の起点になっていて、ARSessionを起動しないと実際にARジャイロ機構取得機能がオンにならず、
・機能がオンにならないと値を吐き出すDevice = ARジャイロ機能が取得できない
という感じになっている。
で、Systemごとにデバイスを取得する方法も異なり、たとえば端末のAR位置 + 回転を取得する機能は、onChangedイベントと同期的な取得の2種があるが、
FaceTrackingとかにはそういうのはない。
抽象化するにしてもいろんなOSのいろんな端末側の都合をいい感じに抽象化できなかったんだろうなあ、、、って感じがすげーある。
実際にARFoundationに用意されている端末の位置+回転を取得する場合、(続く)、、、
それぞれのComponentについて
ARFoundationパッケージに含まれているものを書いていく。
・ARSessionがactiveだったらARFoundationの機能全体を起動する
これが最終的なオンオフになっている。
・ARInputManagerがactiveだったらXRInputSystemを起動する
XRInputSystemは端末の回転やAR空間での移動を把握するためのシステムになっている。
・ARSessionOriginがactiveだったら、セットされているCameraの参照、、、(続く)
・ARFaceManagerがactiveだったら、ARSessionOrigin経由で、、、(続く)
・ARPoseDriverがactiveだったら、AR空間ないでの位置取得やカメラ
実際にはXRInputSystemがStartしている + ARSession(元締め)がactiveであり、そのstateが一定の域を超えたときに
端末の回転やAR空間での移動値を取得するためのデバイスの参照を取り出し、
現在このコンポーネントがついているオブジェクト = カメラのtransforn(posやrot)をいじっている。
そんなあ、、、ってくらい面倒臭い。
ちなみにこの機能は端末のAR空間上の位置と回転の両方を取得できない場合はなんとデバイスの取得を諦めるため、
ARSessionの「何をTrackするか」設定、requestedTrackingMode がRotationOnlyとかだと見事にデバイスの取得に失敗する。
そんなバカな。
おまけで、
ARPoseDriverかTrackedPoseDriverのどちらかがARSessionOriginについてるCameraから発見できないと、ARSessionOriginはwarningを吐いてくる。
TrackedPoseDriverってやつを代わりに使えば回転だけとか取得できたりする? そう思って試してみたが、、、(続く)、、結論から言うとだめだった。
ちなみにARPoseDriverのほうが後発です。
・ARCameraManagerは、、、(続く)
カメラ経由の情報取得をfrontからやるかbackからやるかを指定したりする。
これまたなんか大変そうだなあ、、、、
使わない機能がオンになっても無視すればいいんじゃない?に対してペナルティがある
これはものすごい不満なんだけど、ARFoundationがデフォルトで用意してくれているComponentは、痒いところに対して手が届くものではない。
・ARPoseDriverとかはARSesionの設定によってなんと起動しないので位置や回転が取れなくなる、つまり使わないという選択肢が取れない。
・使わない機能を使わないまま放置すると、なんと毎秒warningがOS側から出たりする
・当然負荷もすごい。最小機能とデフォルトでCPU usageが倍くらい違う。具体的には30%ですむところが60%以上食ったりする。やってられねえ。
ということで最小構成を探究する羽目になった。うーーーーーん、、、、、
Componentが相互に依存する形になっていてしかも関係性を俯瞰できる図がないので、
トライアンドエラー on 実機が最悪の体験をもたらしてくれたのは根に持っている。
でも使うんでしょ?
使う。Unity標準使ってた方が楽なので、、、